unit NTCustomControls;

{$IFDEF FPC}
{$mode objfpc}{$H+}
{$ENDIF}
{$DEFINE 2.4.3} //Change this definition if you're using FPC 2.4.2 or bellow

interface

uses
{$IFDEF FPC}
  LResources, LMessages, LCLType,
{$ELSE}
  {$IFNDEF VER130BELOW}
  Windows, Messages,
  {$ENDIF}
{$ENDIF}
  Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, MaskEdit, Menus,
  Buttons, ComCtrls,

  { Norsenet }
  NTTypes;

type

  { TNTEdit }

  TNTEdit = class(TEdit)
  private
    { Private declarations }
    FColor         : TColor;
    FAttributes    : TAttributes;
    FTextAlign     : TTextAlign;
    FMarked,
    FHilightChanges: Boolean;
    FOldValue      : String;
    function  GetTextAlign: TTextAlign;
    procedure SetAttributes(const AValue: TAttributes);
    procedure SetTextAlign(const AValue: TTextAlign);
  protected
    { Protected declarations }
    procedure DoEnter; override;
    procedure DoExit; override;
    procedure KeyPress(var Key: Char); override;
    procedure Change; override;
  public
    { Public declarations }
    constructor Create(AOwner: TComponent); override;
  published
    { Published declarations }
    property Attributes: TAttributes
      read FAttributes write SetAttributes;
    property TextAlign: TTextAlign
      read GetTextAlign write SetTextAlign default taLeft;
    property HilightChanges: Boolean
      read FHilightChanges write FHilightChanges default True;
  end;

  { TNTNumericEdit }

  TNTNumericEdit = class(TNTEdit)
  private
    { Private declarations }
    FEditType        : TEditType;
    FDecimals        : Byte;
    FCurrencySymbol,
    FDecimalSeparator: String;
    FNegativeColor,
    FFontColor       : TColor;
    function GetEditType: TEditType;
    function GetCurrencySymbol: String;
    function GetDecimals: Byte;
    function GetDecimalSeparator: String;
    function GetFloatValue: Extended;
    function GetIntValue: Integer;
    function GetNegativeColor: TColor;
    procedure SetEditType(const AValue: TEditType);
    procedure SetCurrencySymbol(const AValue: String);
    procedure SetDecimals(const AValue: Byte);
    procedure SetAttributes(const AValue: TAttributes);
    procedure SetFloatValue(const AValue: Extended);
    procedure SetNegativeColor(const AValue: TColor);
    procedure WhenExit;
  protected
    { Protected declarations }
    procedure DoEnter; override;
    procedure DoExit; override;
    procedure KeyPress(var Key: Char); override;
    procedure Change; override;
  public
    { Public declarations }
    constructor Create(AOwner: TComponent); override;
  published
    { Published declarations }
    property EditType: TEditType
      read GetEditType write SetEditType default etInteger;
    property CurrencySymbol: String
      read GetCurrencySymbol write SetCurrencySymbol;
    property Decimals: Byte
      read GetDecimals write SetDecimals default 2;
    property NegativeColor: TColor
      read GetNegativeColor write SetNegativeColor default clRed;
    property DecimalSeparator: String
      read GetDecimalSeparator;
    property IntValue: Integer
      read GetIntValue;
    property FloatValue: Extended
      read GetFloatValue;
    property Value: Extended
      read GetFloatValue write SetFloatValue;
  end;

  { TNTComboBox }

  TNTComboBox = class(TComboBox)
  private
    { Private declarations }
    FAttributes: TAttributes;
    FColor     : TColor;
  protected
    { Protected declarations }
    procedure DoEnter; override;
    procedure DoExit; override;
    procedure KeyPress(var Key: Char); override;
  public
    { Public declarations }
    constructor Create(AOwner: TComponent); override;
  published
    { Published declarations }
    property Attributes: TAttributes
      read FAttributes write FAttributes;
  end;

  { TNTCheckBox }

  TNTCheckBox = class(TCheckBox)
  private
    FBoxState,
    FMarked,
    FHilightChanges: Boolean;
    function GetHilightChanges: Boolean;
    procedure SetHilightChanges(const AValue: Boolean);
  public
    constructor Create(AOwner: TComponent); override;
    procedure DoEnter; override;
    procedure Click; override;
    procedure KeyPress(var Key: Char); override;
  published
    property HilightChanges: Boolean
      read GetHilightChanges write SetHilightChanges default True;
  end;

  { TNTRadioButton }

  TNTRadioButton = class(TRadioButton)
  private
    FHilightChanges: Boolean;
    function GetHilightChanges:Boolean;
    procedure SetHilightChanges(const AValue: Boolean);
  public
    constructor Create(AOwner: TComponent); override;
    {$IFDEF 2.4.3}
    procedure DoClickOnChange; override;
    {$ELSE}
    procedure DoChange(var Msg); message LM_CHANGED;
    {$ENDIF}
  published
    property HilightChanges: Boolean
      read GetHilightChanges write SetHilightChanges default True;
  end;

  { TNTMaskEdit }

  TNTMaskEdit = class(TMaskEdit)
  private
    FColor             : TColor;
    FAttributes        : TAttributes;
    FSaveLiterals,
    FValidate,
    FMarked,
    FHilightChanges    : Boolean;
    FOldValue          : String;
    FMaskType          : TMaskType;
    FAlternate         : TAlternableMask;
    FCharForBlanks     : Char;
    FControlMask       : Byte;
    FAlternableShortCut: TShortCut;
    procedure SetAttributes(const AValue: TAttributes);
    procedure SetMask(const AValue: TMaskType);
    procedure SetValidate(const AValue: Boolean);
  protected
    { Protected declarations }
    procedure DoEnter; override;
    procedure DoExit; override;
    procedure KeyPress(var Key: Char); override;
    procedure Change; override;
    procedure KeyUp(var Key: Word; Shift: TShiftState); override;
  public
    { Public declarations }
    constructor Create(AOwner: TComponent); override;
  published
    { Published declarations }
    property Attributes: TAttributes
      read FAttributes write SetAttributes;
    property HilightChanges: Boolean
      read FHilightChanges write FHilightChanges default True;
    property Validate: Boolean
      read FValidate write SetValidate default True;
    property SaveLiterals: Boolean
      read FSaveLiterals write FSaveLiterals default False;
    property MaskType: TMaskType
      read FMaskType write SetMask;
    property AlternableMasks: TAlternableMask
      read FAlternate write FAlternate;
    property CharForBlanks: Char
      read FCharForBlanks write FCharForBlanks;
    property AlternableShortCut: TShortCut
      read FAlternableShortCut write FAlternableShortCut;

  end;

  { TNTMemo }

  TNTMemo = class(TMemo)
  private
    { Private declarations }
    FColor         : TColor;
    FAttributes    : TAttributes;
    FMarked,
    FHilightChanges: Boolean;
    FOldValue      : String;
    procedure SetAttributes(const AValue: TAttributes);
  protected
    { Protected declarations }
    procedure DoEnter; override;
    procedure DoExit; override;
    procedure KeyDown(var Key: Word; Shift: TShiftState); override;
    procedure Change; override;
  public
    { Public declarations }
    constructor Create(AOwner: TComponent); override;
  published
    { Published declarations }
    property Attributes: TAttributes
      read FAttributes write SetAttributes;
    property HilightChanges: Boolean
      read FHilightChanges write FHilightChanges default True;
  end;

  procedure AlignRight(AEdt: TNTEdit);
  function  DDDCheck(ADDD: Byte): Boolean;
  function  CPFCheck(ACPF: String): Boolean;
  function  CNPJCheck(ACNPJ: String): Boolean;
  function  PISCheck(APIS: String): Boolean;

implementation

procedure AlignRight(AEdt: TNTEdit);
begin
  //TODO
end;

function DDDCheck(ADDD: Byte): Boolean;
begin
  Result := ADDD in [11..19, 21, 22, 24, 27, 28, 31..35, 37, 38, 41..49, 51, 53..55, 61..69,
                     71, 73..77, 79, 81..89, 91..99];
end;

function CPFCheck(ACPF: String): Boolean;
var
  n1, n2, n3, n4, n5, n6, n7, n8, n9, d1, d2: Integer;
  rDigitado, rCalculado: String;
  rRet: Boolean;
begin
  rRet := True;
  ACPF := StringReplace(StringReplace(ACPF, '.', '', [rfReplaceAll]), '-', '', [rfReplaceAll]);
  n1 := StrToInt(ACPF[1]);
  n2 := StrToInt(ACPF[2]);
  n3 := StrToInt(ACPF[3]);
  n4 := StrToInt(ACPF[4]);
  n5 := StrToInt(ACPF[5]);
  n6 := StrToInt(ACPF[6]);
  n7 := StrToInt(ACPF[7]);
  n8 := StrToInt(ACPF[8]);
  n9 := StrToInt(ACPF[9]);

  d1 := n9* 2 + n8 * 3 + n7 * 4 + n6 * 5 + n5 * 6 + n4 * 7 + n3 * 8 + n2 * 9 + n1 * 10;
  d1 := 11 - (d1 mod 11);

  if d1 >= 10 then
    d1 := 0;

  d2 := d1 * 2 + n9 * 3 + n8 * 4 + n7 * 5 + n6 * 6 + n5 * 7 + n4 * 8 + n3 * 9 + n2 * 10 + n1 * 11;
  d2 := 11 - (d2 mod 11);

  if d2 >= 10 then
    d2 := 0;

  rRet := (ACPF <> '00000000000') and (ACPF <> '11111111111') and (ACPF <> '22222222222') and
          (ACPF <> '33333333333') and (ACPF <> '44444444444') and (ACPF <> '55555555555') and
          (ACPF <> '66666666666') and (ACPF <> '77777777777') and (ACPF <> '88888888888') and
          (ACPF <> '99999999999');

  rCalculado := IntToStr(d1) + IntToStr(d2);
  rDigitado := ACPF[10] + ACPF[11];

  Result := (rDigitado = rCalculado) and rRet;
end;

function CNPJCheck(ACNPJ: String): Boolean;
var
  rCNPJ: String;
  dg1, dg2, x, rTotal: Integer;
  rRet: Boolean;
begin
  rRet := False;
  rCNPJ := '';

  //Analisa os formatos
  if Length(ACNPJ) = 18 then
    if (Copy(ACNPJ, 3, 1) + Copy(ACNPJ, 7, 1) + Copy(ACNPJ, 11, 1) + Copy(ACNPJ, 16, 1) = '../-') then
    begin
      rCNPJ := Copy(ACNPJ, 1, 2) + Copy(ACNPJ, 4, 3) + Copy(ACNPJ, 8, 3) + Copy(ACNPJ, 12, 4) +
               Copy(ACNPJ, 17, 2);
      rRet := True;
    end;

  if Length(ACNPJ) = 14 then
  begin
    rCNPJ := ACNPJ;
    rRet := True;
  end;

  //Verifica
  if rRet then
  begin
    try
      //1° digito
      rTotal := 0;
      for x := 1 to 12 do
      begin
        if x < 5 then
          Inc(rTotal, StrToInt(Copy(rCNPJ, x, 1)) * (6 - x))
        else
          Inc(rTotal, StrToInt(Copy(rCNPJ, x, 1)) * (14 - x));
      end;

      dg1 := 11 - (rTotal mod 11);

      if dg1 > 9 then
        dg1 := 0;

      //2° digito
      rTotal := 0;
      for x := 1 to 13 do
      begin
        if x < 6 then
          Inc(rTotal, StrToInt(Copy(rCNPJ, x, 1)) * (7 - x))
        else
          Inc(rTotal, StrToInt(Copy(rCNPJ, x, 1)) * (15 - x));
      end;

      dg2 := 11 - (rTotal mod 11);

      if dg2 > 9 then
        dg2 := 0;

      //Validação final
      if (dg1 = StrToInt(Copy(rCNPJ, 13, 1))) and (dg2 = StrToInt(Copy(rCNPJ, 14, 1))) then
        rRet := True
      else
        rRet := False;
    except
      rRet := False;
    end;

    //Inválidos
    rRet := ((rCNPJ <> '00000000000000') and (rCNPJ <> '11111111111111') and (rCNPJ <> '22222222222222') and
             (rCNPJ <> '33333333333333') and (rCNPJ <> '44444444444444') and (rCNPJ <> '55555555555555') and
             (rCNPJ <> '66666666666666') and (rCNPJ <> '77777777777777') and (rCNPJ <> '88888888888888') and
             (rCNPJ <> '99999999999999')) and rRet;
  end;

  Result := rRet;
end;

function PISCheck(APIS: String): Boolean;
var
  i, rSoma, rM11, rDV, rDigito: Integer;
begin
  if Trim(APIS) <> '' then
  begin
    rDV := StrToInt(copy(APIS,11,1));
    rSoma := 0;
    rM11 := 2;

    for i := 1 to 10 do
    begin
      rSoma := rSoma + (rM11 * StrToInt(Copy(APIS,11 -i, 1)));

      if rM11 < 9 then
        rM11 := rM11+1
      else
        rM11 := 2;
    end;

    rDigito := 11 - (rSoma mod 11);

    if rDigito > 9 then
      rDigito := 0;

    Result := rDV = rDigito;
  end
  else
    Result := False;
end;

{ TNTNumericEdit }

procedure TNTNumericEdit.SetAttributes(const AValue: TAttributes);
begin
  FAttributes.Assign(AValue);
end;

procedure TNTNumericEdit.SetFloatValue(const AValue: Extended);
begin
  Text := FloatToStr(AValue);
  WhenExit;
end;

procedure TNTNumericEdit.SetNegativeColor(const AValue: TColor);
begin
  if FNegativeColor <> AValue then
    FNegativeColor := AValue;
end;

procedure TNTNumericEdit.WhenExit;
var
  eValue: Extended;
  sFormat: String;
  bLenght: Byte;
begin
  if Text = '' then
    Text := '0';

  bLenght := Length(Text);

  if FDecimals > 0 then
  begin
    if AnsiPos(',', Text) = 0 then
      Text := Text + ',';

    while Length(Text) < bLenght + FDecimals do
      Text := Text + '0';

    sFormat := '######0.';

    while Length(sFormat) < 8 + FDecimals do
      sFormat := sFormat + '0';
  end;

  eValue := StrToFloat(Text);

  case FEditType of
    etCurrency: Text := FCurrencySymbol + ' ' + FormatFloat(sFormat, eValue);
    etPercent : Text := FormatFloat(sFormat, eValue) + '%';
    etFloat   : Text := FormatFloat(sFormat, eValue);
    etInteger : Text := FormatFloat('#########0', eValue);
  end;

  if GetFloatValue < 0 then
    Font.Color := FNegativeColor
  else
    Font.Color := FFontColor;
end;

procedure TNTNumericEdit.DoEnter;
begin
  case FEditType of
    etCurrency: 
    begin
      Text := Trim(StringReplace(Text, FCurrencySymbol, '', [rfReplaceAll]));
      SelStart := 0;
      SelLength := Length(Text);
    end;
    etPercent :
    begin
      Text := Trim(StringReplace(Text, '%', '', [rfReplaceAll]));
      SelStart := 0;
      SelLength := Length(Text);
    end;
  end;

  FOldValue := Text;

  inherited DoEnter;
end;

procedure TNTNumericEdit.DoExit;
begin
  WhenExit;
  inherited DoExit;
end;

procedure TNTNumericEdit.KeyPress(var Key: Char);
var
  eTest: Extended;
begin
  case FEditType of
    etInteger : if (not (Key in ['0'..'9', #8, #13, #27, '-'])) then
                  Key := #0;
    etFloat,
    etCurrency,
    etPercent :
    begin
      if (not (Key in ['0'..'9', #8, #13, #27, ',', '-'])) then
        Key := #0;

      if (AnsiPos(',', Text) > 0) and (Key = ',') then
        Key := #0;
    end;
  end;

  if Key = '-' then
  begin
    if SelLength = Length(Text) then
    begin
      inherited KeyPress(Key);
      Exit;
    end;

    if AnsiPos('-', Text) > 0 then
      Key := #0
    else
      if Length(Text) > 0 then
        Key := #0;
  end;

  inherited KeyPress(Key);
end;

procedure TNTNumericEdit.Change;
var
  extValue, extOldValue: Extended;
  strTmp: String;
begin
  extValue := 0;
  extOldValue := 0;

  strTmp := StringReplace(Text, FCurrencySymbol, '', [rfReplaceAll]);
  strTmp := StringReplace(strTmp, '%', '', [rfReplaceAll]);
  strTmp := Trim(strTmp);

  if strTmp = '' then
    strTmp := '0';

  try
    try
      if Text <> '' then
      begin
        extValue := StrToFloat(strTmp);

        if FOldValue = '' then
          extOldValue := 0
        else
          extOldValue := StrToFloat(FOldValue);
      end;
    except
    end;
  finally
    if FHilightChanges and Focused then
    begin
      if (extValue <> extOldValue) and (extOldValue <> 0) and
         ((AnsiPos(FCurrencySymbol, Text) > 0) or (AnsiPos('%', Text) > 0)) then
        Font.Style := Font.Style + [fsBold]
      else
        Font.Style := Font.Style - [fsBold];
    end;

    inherited Change;
  end;
end;

constructor TNTNumericEdit.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FFontColor := Font.Color;
  FDecimalSeparator := ',';
  SetCurrencySymbol('R$');
  SetDecimals(0);
  SetEditType(etInteger);
  SetTextAlign(taRight);
  SetNegativeColor(clRed);
  SetFloatValue(0);
end;

function TNTNumericEdit.GetEditType: TEditType;
begin
  Result := FEditType;
end;

procedure TNTNumericEdit.SetEditType(const AValue: TEditType);
begin
  if FEditType <> AValue then
  begin
    FEditType := AValue;
    case FEditType of
      etInteger : SetDecimals(0);
      etFloat,
      etCurrency,
      etPercent : SetDecimals(2);
    end;

    case FEditType of
      etInteger: Text := '0';
    end;
  end;
end;

function TNTNumericEdit.GetCurrencySymbol: String;
begin
  Result := FCurrencySymbol;
end;

function TNTNumericEdit.GetDecimals: Byte;
begin
  Result := FDecimals;
end;

function TNTNumericEdit.GetDecimalSeparator: String;
begin
  Result := FDecimalSeparator;
end;

function TNTNumericEdit.GetFloatValue: Extended;
var
  sValue: String;
begin
  try
    case FEditType of
      etInteger,
      etFloat   : sValue := Text;
      etCurrency: sValue := Trim(StringReplace(Text, FCurrencySymbol, '', [rfReplaceAll]));
      etPercent : sValue := Trim(StringReplace(Text, '%', '', [rfReplaceAll]));
    end;

    if sValue = '' then
      sValue := '0';

    Result := StrToFloat(sValue);

    if Result < 0 then
      Font.Color := FNegativeColor
    else
      Font.Color := FFontColor;
  except
    Result := 0;
  end;
end;

function TNTNumericEdit.GetIntValue: Integer;
var
  sValue: String;
  eValue: Extended;
begin
  try
    case FEditType of
      etInteger,
      etFloat   : sValue := Text;
      etCurrency: sValue := Trim(StringReplace(Text, FCurrencySymbol, '', [rfReplaceAll]));
      etPercent : sValue := Trim(StringReplace(Text, '%', '', [rfReplaceAll]));
    end;

    if sValue = '' then
      sValue := '0';

    eValue := Int(StrToFloat(sValue));
    Result := StrToInt(FormatFloat('#########0', eValue));
  except
    Result := 0;
  end;
end;

function TNTNumericEdit.GetNegativeColor: TColor;
begin
  Result := FNegativeColor;
end;

procedure TNTNumericEdit.SetCurrencySymbol(const AValue: String);
begin
  if FCurrencySymbol <> AValue then
  begin
    if Length(AValue) > 3 then
      Exit;

    if AnsiPos('$', AValue) = 0 then
      FCurrencySymbol := AValue + '$'
    else
      FCurrencySymbol := AValue;
  end;

  if FEditType = etCurrency then
  begin
    case FDecimals of
      2: Text := FCurrencySymbol + ' 0,00';
      3: Text := FCurrencySymbol + ' 0,000';
    end;
  end;
end;

procedure TNTNumericEdit.SetDecimals(const AValue: Byte);
begin
  if FDecimals <> AValue then
  begin
    if FEditType = etInteger then
    begin
      FDecimals := 0;
      Text := '0';
      Exit;
    end;

    if (AValue < 2) and (FEditType = etCurrency) then
      FDecimals := 2
    else if (AValue > 3) and (FEditType = etCurrency) then
      FDecimals := 3
    else
      FDecimals := AValue;
  end;

  case FEditType of
    etCurrency: case FDecimals of
                  2: Text := FCurrencySymbol + ' 0,00';
                  3: Text := FCurrencySymbol + ' 0,000';
                end;
    etFloat   :
    begin
      Text := '0';

      if FDecimals > 0 then
        Text := Text + ',';

      while Length(Text) < 2 + FDecimals do
        Text := Text + '0';
    end;
    etPercent :
    begin
      Text := '0';

      if FDecimals > 0 then
        Text := Text + ',';

      while Length(Text) < 2 + FDecimals do
        Text := Text + '0';

      Text := Text + '%';
    end;
  end;
end;

{ TNTComboBox }

procedure TNTComboBox.DoEnter;
begin
  FColor := Color;

  if FAttributes.Colorize then
    Color := FAttributes.Colors.FocusColor;

  inherited DoEnter;
end;

procedure TNTComboBox.DoExit;
begin
  if FAttributes.Required then
  begin
    if Text = '' then
      Color := FAttributes.Colors.WrongColor
    else
      Color := FAttributes.Colors.RightColor;
  end
  else
    Color := FColor;

  inherited DoExit;
end;

procedure TNTComboBox.KeyPress(var Key: Char);
begin
  case Key of
    #13: if FAttributes.EnterAsTab then
{$IFDEF FPC}
           PerformTab(True);
{$ELSE}
  {$IFNDEF VER130BELOW}
           Perform(WM_NEXTDLGCTL, 0, 0);
  {$ENDIF}
{$ENDIF}
    #27: case FAttributes.EscapeAction of
{$IFDEF FPC}
           eaBack     :PerformTab(False);
{$ELSE}
  {$IFNDEF VER130BELOW}
           eaBack     :Perform(WM_NEXTDLGCTL, 0, -1);
  {$ENDIF}
{$ENDIF}
           eaClear    : Clear;
           eaClearBack: if Text <> '' then
                          Clear
                        else
{$IFDEF FPC}
                          PerformTab(False);
{$ELSE}
  {$IFNDEF VER130BELOW}
                          Perform(WM_NEXTDLGCTL, 0, -1);
  {$ENDIF}
{$ENDIF}
           eaClose    : GetParentForm(TControl(Self)).Close;
         end;
  end;
  inherited KeyPress(Key);
end;

constructor TNTComboBox.Create(AOwner: TComponent);
begin
  FAttributes := TAttributes.Create(Self);
  inherited Create(AOwner);
end;

{ TNTCheckBox }

function TNTCheckBox.GetHilightChanges:Boolean;
begin
  Result := FHilightChanges;
end;

procedure TNTCheckBox.SetHilightChanges(const AValue: Boolean);
begin
  if FHilightChanges <> AValue then
    FHilightChanges := AValue;
end;

constructor TNTCheckBox.Create(AOwner:TComponent);
begin
  inherited Create(AOwner);
  FHilightChanges := True;
  FBoxState := False;
  FMarked := False;
end;

procedure TNTCheckBox.DoEnter;
begin
  if not FMarked then
  begin
    FBoxState := Checked;
    FMarked := True;
  end;

  inherited DoEnter;
end;

procedure TNTCheckBox.Click;
begin
  inherited Click;

  if FHilightChanges then
  begin
    if Checked <> FBoxState then
      Font.Style := Font.Style + [fsBold]
    else
      Font.Style := Font.Style - [fsBold];
  end;
end;

procedure TNTCheckBox.KeyPress(var Key:Char);
begin
  inherited KeyPress(Key);
end;

{ TNTRadioButton }

function TNTRadioButton.GetHilightChanges:Boolean;
begin
  Result := FHilightChanges;
end;

procedure TNTRadioButton.SetHilightChanges(const AValue:Boolean);
begin
  if FHilightChanges <> AValue then
    FHilightChanges := AValue;
end;

constructor TNTRadioButton.Create(AOwner:TComponent);
begin
  inherited Create(AOwner);
  FHilightChanges := True;
end;

{$IFDEF 2.4.3}
procedure TNTRadioButton.DoClickOnChange;
begin
  inherited DoClickOnChange;

  if FHilightChanges then
  begin
    if Checked then
      Font.Style := Font.Style + [fsBold]
    else
      Font.Style := Font.Style - [fsBold];
  end;
end;
{$ELSE}
procedure TNTRadioButton.DoChange(var Msg);
begin
  inherited DoChange(Msg);

  if FHilightChanges then
  begin
    if Checked then
      Font.Style := Font.Style + [fsBold]
    else
      Font.Style := Font.Style - [fsBold];
  end;
end;
{$ENDIF}

{ TNTEdit }

procedure TNTEdit.SetAttributes(const AValue: TAttributes);
begin
  FAttributes.Assign(AValue);
end;

function TNTEdit.GetTextAlign: TTextAlign;
begin
  Result := FTextAlign;
end;

procedure TNTEdit.SetTextAlign(const AValue: TTextAlign);
begin
  if FTextAlign <> AValue then
  begin
    if FTextAlign = taRight then
      AlignRight(Self);
  end;
end;

procedure TNTEdit.DoEnter;
begin
  FColor := Color;

  if FAttributes.Colorize then
    Color := FAttributes.Colors.FocusColor;

  if not FMarked then
  begin
    FOldValue := Text;
    FMarked := True;
  end;

  inherited DoEnter;
end;

procedure TNTEdit.DoExit;
begin
  if FAttributes.Required then
  begin
    if Text = '' then
      Color := FAttributes.Colors.WrongColor
    else
      Color := FAttributes.Colors.RightColor;
  end
  else
    Color := FColor;

  inherited DoExit;
end;

procedure TNTEdit.KeyPress(var Key: Char);
begin
    case Key of
    #13: if FAttributes.EnterAsTab then
{$IFDEF FPC}
           PerformTab(True);
{$ELSE}
  {$IFNDEF VER130BELOW}
           Perform(WM_NEXTDLGCTL, 0, 0);
  {$ENDIF}
{$ENDIF}
    #27: case FAttributes.EscapeAction of
{$IFDEF FPC}
           eaBack     :PerformTab(False);
{$ELSE}
  {$IFNDEF VER130BELOW}
           eaBack     :Perform(WM_NEXTDLGCTL, 0, -1);
  {$ENDIF}
{$ENDIF}
           eaClear    : Clear;
           eaClearBack: if Text <> '' then
                          Clear
                        else
{$IFDEF FPC}
                          PerformTab(False);
{$ELSE}
  {$IFNDEF VER130BELOW}
                          Perform(WM_NEXTDLGCTL, 0, -1);
  {$ENDIF}
{$ENDIF}
           eaClose    : GetParentForm(TControl(Self)).Close;
         end;
  end;

  inherited KeyPress(Key);
end;

procedure TNTEdit.Change;
begin
  if FHilightChanges and FMarked and Focused then
  begin
    if (Text <> FOldValue) and (FOldValue <> '') then
      Font.Style := Font.Style + [fsBold]
    else
      Font.Style := Font.Style - [fsBold];
  end;

  inherited Change;
end;

constructor TNTEdit.Create(AOwner: TComponent);
begin
  FAttributes := TAttributes.Create(Self);
  FMarked := False;
  FOldValue := '';
  FHilightChanges := True;
  inherited Create(AOwner);
end;

{ TNTMaskEdit }

procedure TNTMaskEdit.SetAttributes(const AValue: TAttributes);
begin
  FAttributes.Assign(AValue);
end;

procedure TNTMaskEdit.SetMask(const AValue: TMaskType);
var
  rLiterals: String;
begin
  case FSaveLiterals of
    True : rLiterals := '1';
    False: rLiterals := '0';
  end;

  FMaskType := AValue;

  case AValue of
    mtTelefone,
    mtTelFixo,
    mtCelular : EditMask := '(##)####-####;' + rLiterals + ';' + FCharForBlanks;
    mtCPF     : EditMask := '###.###.###-##;' + rLiterals + ';' + FCharForBlanks;
    mtCNPJ    : EditMask := '##.###.###/####-##;' + rLiterals + ';' + FCharForBlanks;
    mtPIS     : EditMask := '###.######-##;' + rLiterals + ';' + FCharForBlanks;
    mtData    :
    begin
      FSaveLiterals := True;
      EditMask := '##/##/####;1;' + FCharForBlanks;
    end;
    mtPlaca   :
    begin
      EditMask := 'AAA-9999;' + rLiterals + ';' + FCharForBlanks;
      SetCharCase(ecUppercase);
    end;
  end;
end;

procedure TNTMaskEdit.SetValidate(const AValue: Boolean);
begin
  if FValidate <> AValue then
    FValidate := AValue;

  if FValidate then
    FAttributes.Colorize := True;
end;

procedure TNTMaskEdit.DoEnter;
begin
  FColor := Color;

  if FAttributes.Colorize then
    Color := FAttributes.Colors.FocusColor;

  if not FMarked then
  begin
    FOldValue := Text;
    FMarked := True;
  end;

  inherited DoEnter;
end;

procedure TNTMaskEdit.DoExit;
{begin
  if FAttributes.Required then
  begin
    if Text = '' then
      Color := FAttributes.Colors.WrongColor
    else
      Color := FAttributes.Colors.RightColor;
  end
  else
    Color := FColor;

  inherited DoExit;
end;}
var
  rStr1, rStr2: String;
  rData: TDate;
begin
  rStr1 := StringReplace(Text, '(', '', [rfReplaceAll]);
  rStr1 := StringReplace(rStr1, ')', '', [rfReplaceAll]);
  rStr1 := StringReplace(rStr1, '-', '', [rfReplaceAll]);
  rStr1 := StringReplace(rStr1, '.', '', [rfReplaceAll]);
  rStr1 := StringReplace(rStr1, '/', '', [rfReplaceAll]);

  if FAttributes.Required then
  begin
    case FMaskType of
      mtTelefone:
      begin
        try
          if rStr1 = '' then
          begin
            Color := FAttributes.Colors.WrongColor;
            Exit;
          end;

          rStr2 := Copy(rStr1, 1, 2);
          rStr1 := Copy(rStr1, 3, 8);

          if FValidate then
          begin
            if (StrToInt64(rStr1) > 20000000) and (DDDCheck(StrToInt(rStr2))) then
              Color := FAttributes.Colors.RightColor
            else
              begin
                Color := FAttributes.Colors.WrongColor;
                Exit;
              end;
          end;
        except
          on EConvertError do
          begin
            Color := FAttributes.Colors.WrongColor;
            Exit;
          end;
        end;
      end;
      mtTelFixo:
      begin
        try
          if rStr1 = '' then
          begin
            Color := FAttributes.Colors.WrongColor;
            Exit;
          end;

          rStr2 := Copy(rStr1, 1, 2);
          rStr1 := Copy(rStr1, 3, 8);

          if FValidate then
          begin
            if (StrToInt64(rStr1) > 20000000) and (StrToInt64(rStr1) < 69999999) and
               (DDDCheck(StrToInt(rStr2))) then
              Color := FAttributes.Colors.RightColor
            else
              begin
                Color := FAttributes.Colors.WrongColor;
                Exit;
              end;
          end;
        except
          on EConvertError do
          begin
            Color := FAttributes.Colors.WrongColor;
            Exit;
          end;
        end;
      end;
      mtCelular:
      begin
        try
          if rStr1 = '' then
          begin
            Color := FAttributes.Colors.WrongColor;
            Exit;
          end;

          rStr2 := Copy(rStr1, 1, 2);
          rStr1 := Copy(rStr1, 3, 8);

          if FValidate then
          begin
            if (StrToInt64(rStr1) > 70000000) and (DDDCheck(StrToInt(rStr2))) then
              Color := FAttributes.Colors.RightColor
            else
              begin
                Color := FAttributes.Colors.WrongColor;
                Exit;
              end;
          end;
        except
          on EConvertError do
          begin
            Color := FAttributes.Colors.WrongColor;
            Exit;
          end;
        end;
      end;
      mtCPF:
      begin
        if rStr1 = '' then
        begin
          Color := FAttributes.Colors.WrongColor;
          Exit;
        end;

        if FValidate then
        begin
          if CPFCheck(rStr1) then
            Color := FAttributes.Colors.RightColor
          else
            begin
              Color := FAttributes.Colors.WrongColor;
              Exit;
            end;
        end;
      end;
      mtCNPJ:
      begin
        if rStr1 = '' then
        begin
          Color := FAttributes.Colors.WrongColor;
          Exit;
        end;

        if FValidate then
        begin
          if CNPJCheck(rStr1) then
            Color := FAttributes.Colors.RightColor
          else
            begin
              Color := FAttributes.Colors.WrongColor;
              Exit;
            end;
        end;
      end;
      mtPIS:
      begin
        if rStr1 = '' then
        begin
          Color := FAttributes.Colors.WrongColor;
          Exit;
        end;

        if FValidate then
        begin
          if PISCheck(rStr1) then
            Color := FAttributes.Colors.RightColor
          else
            begin
              Color := FAttributes.Colors.WrongColor;
              Exit;
            end;
        end;
      end;
      mtData:
      begin
        rStr1 := Copy(rStr1, 1, 2) + '/' + Copy(rStr1, 3, 2) + '/' + Copy(rStr1, 5, 4);
        try
          rData := StrToDate(rStr1);
          Color := FAttributes.Colors.RightColor;
        except
          on EConvertError do
          begin
            Color := FAttributes.Colors.WrongColor;
            Exit;
          end;
        end;
      end;
    end;
  end
  else
    Color := FColor;
  inherited;
end;

procedure TNTMaskEdit.KeyPress(var Key: Char);
begin
  case Key of
    #13: if FAttributes.EnterAsTab then
{$IFDEF FPC}
           PerformTab(True);
{$ELSE}
  {$IFNDEF VER130BELOW}
           Perform(WM_NEXTDLGCTL, 0, 0);
  {$ENDIF}
{$ENDIF}
    #27: case FAttributes.EscapeAction of
{$IFDEF FPC}
           eaBack     :PerformTab(False);
{$ELSE}
  {$IFNDEF VER130BELOW}
           eaBack     :Perform(WM_NEXTDLGCTL, 0, -1);
  {$ENDIF}
{$ENDIF}
           eaClear    : Clear;
           eaClearBack: if Text <> '' then
                          Clear
                        else
{$IFDEF FPC}
                          PerformTab(False);
{$ELSE}
  {$IFNDEF VER130BELOW}
                          Perform(WM_NEXTDLGCTL, 0, -1);
  {$ENDIF}
{$ENDIF}
           eaClose    : GetParentForm(TControl(Self)).Close;
         end;
  end;

  inherited KeyPress(Key);
end;

procedure TNTMaskEdit.Change;
begin
  if FHilightChanges and FMarked and Focused then
  begin
    if (Text <> FOldValue) and (FOldValue <> '') then
      Font.Style := Font.Style + [fsBold]
    else
      Font.Style := Font.Style - [fsBold];
  end;

  inherited Change;
end;

procedure TNTMaskEdit.KeyUp(var Key: Word; Shift: TShiftState);
var
  i: Byte;
begin
  if ssCtrl in Shift then
    Key := Key + 16384;

  if Key = FAlternableShortCut then
  begin
    i := FControlMask;
    while i <= 7 do
    begin
      if (i = 7) and (not (amPIS in FAlternate)) then
        i := 0;

      case i of
        0:
        begin
          if (FMaskType <> mtTelefone) and (amTelefone in FAlternate) then
          begin
            SetMask(mtTelefone);
            Break;
          end;
        end;
        1:
        begin
          if (FMaskType <> mtTelFixo) and (amTelFixo in FAlternate) then
          begin
            SetMask(mtTelFixo);
            Break;
          end;
        end;
        2:
        begin
          if (FMaskType <> mtCelular) and (amCelular in FAlternate) then
          begin
            SetMask(mtCelular);
            Break;
          end;
        end;
        3:
        begin
          if (FMaskType <> mtCPF) and (amCPF in FAlternate) then
          begin
            SetMask(mtCPF);
            Break;
          end;
        end;
        4:
        begin
          if (FMaskType <> mtCNPJ) and (amCNPJ in FAlternate) then
          begin
            SetMask(mtCNPJ);
            Break;
          end;
        end;
        5:
        begin
          if (FMaskType <> mtData) and (amData in FAlternate) then
          begin
            SetMask(mtData);
            Break;
          end;
        end;
        6:
        begin
          if (FMaskType <> mtPlaca) and (amPlaca in FAlternate) then
          begin
            SetMask(mtPlaca);
            FControlMask := 0;
            Break;
          end;
        end;
        7:
        begin
          if (FMaskType <> mtPIS) and (amPIS in FAlternate) then
          begin
            SetMask(mtPIS);
            FControlMask := 0;
            Break;
          end;
        end;
      end;

      inc(i);
      FControlMask := i;
    end;
  end;
  inherited KeyUp(Key, Shift);
end;

constructor TNTMaskEdit.Create(AOwner: TComponent);
begin
  FAttributes := TAttributes.Create(Self);
  FMarked := False;
  FOldValue := '';
  FHilightChanges := True;
  FCharForBlanks := #32;
  FSaveLiterals := False;
  FControlMask := 0;
  SetMask(mtCustom);
  SetValidate(True);
  inherited Create(AOwner);
end;

{ TNTMemo }

procedure TNTMemo.SetAttributes(const AValue: TAttributes);
begin
  FAttributes.Assign(AValue);
end;

procedure TNTMemo.DoEnter;
begin
  FColor := Color;

  if FAttributes.Colorize then
    Color := FAttributes.Colors.FocusColor;

  if not FMarked then
  begin
    FOldValue := Text;
    FMarked := True;
  end;

  inherited DoEnter;
end;

procedure TNTMemo.DoExit;
begin
  if FAttributes.Required then
  begin
    if Text = '' then
      Color := FAttributes.Colors.WrongColor
    else
      Color := FAttributes.Colors.RightColor;
  end
  else
    Color := FColor;

  inherited DoExit;
end;

procedure TNTMemo.KeyDown(var Key: Word; Shift: TShiftState);
begin
  case Key of
    13:
    begin
      if ssCtrl in Shift then
        NewLine
      else
        begin
          Key := 0;
{$IFDEF FPC}
          PerformTab(True);
{$ELSE}
  {$IFNDEF VER130BELOW}
          Perform(WM_NEXTDLGCTL, 0, 0);
  {$ENDIF}
{$ENDIF}
        end;
    end;
    27: case FAttributes.EscapeAction of
{$IFDEF FPC}
           eaBack     :PerformTab(False);
{$ELSE}
  {$IFNDEF VER130BELOW}
           eaBack     :Perform(WM_NEXTDLGCTL, 0, -1);
  {$ENDIF}
{$ENDIF}
           eaClear    : Clear;
           eaClearBack: if Text <> '' then
                          Clear
                        else
{$IFDEF FPC}
                          PerformTab(False);
{$ELSE}
  {$IFNDEF VER130BELOW}
                          Perform(WM_NEXTDLGCTL, 0, -1);
  {$ENDIF}
{$ENDIF}
           eaClose    : GetParentForm(TControl(Self)).Close;
         end;
  end;

  inherited KeyDown(Key, Shift);
end;

procedure TNTMemo.Change;
begin
  if FHilightChanges and FMarked and Focused then
  begin
    if (Text <> FOldValue) and (FOldValue <> '') then
      Font.Style := Font.Style + [fsBold]
    else
      Font.Style := Font.Style - [fsBold];
  end;

  inherited Change;
end;

constructor TNTMemo.Create(AOwner: TComponent);
begin
  FAttributes := TAttributes.Create(Self);
  FHilightChanges := True;
  WantReturns := False;
  inherited Create(AOwner);
end; 

end.
